#include "serial.h"

#include <QDebug>
#include <QSerialPortInfo>

#define SYNC_CODE 0x55
#define DATA_SIZE_MAX 252

#define VID 0x1a86
#define PID 0x7523

Serial::Serial(QObject *parent)
    : QObject{parent}
{
    serialport = new QSerialPort(parent);
    serialport->setBaudRate(QSerialPort::Baud9600);
    serialport->setDataBits(QSerialPort::Data8);
    serialport->setParity(QSerialPort::NoParity);
    serialport->setStopBits(QSerialPort::OneStop);
    serialport->setFlowControl(QSerialPort::NoFlowControl);

    frameTimer.setInterval(100);
    frameTimer.setSingleShot(true);

    connect(&frameTimer, &QTimer::timeout, this, &Serial::onFrameEnd);
    connect(serialport, &QSerialPort::readyRead, this, &Serial::onReadyRead);
}

Serial::~Serial()
{
    frameTimer.stop();
    close();
    delete serialport;
}

QStringList Serial::availablePorts()
{
    QStringList ports;

    const auto infos = QSerialPortInfo::availablePorts();
    for(const auto &info : infos)
    {
        // if((info.vendorIdentifier() == VID) && (info.productIdentifier() == PID))
        {
            ports.append(info.portName());
        }
    }

    return ports;
}

bool Serial::open(const QString &portName)
{
    if(serialport->isOpen()) {
        serialport->close();
    }

    bool connected = false;
    serialport->setPortName(portName);
    if(serialport->open(QIODevice::ReadWrite))
    {
        connected = true;
    }

    emit connectionChanged(connected);
    return connected;
}

bool Serial::isOpen()
{
    return serialport->isOpen();
}

void Serial::close()
{
    if(serialport->isOpen())
    {
        serialport->close();
        emit connectionChanged(isOpen());
    }

    if(frameTimer.isActive())
    {
        frameTimer.stop();
    }
}

QString Serial::connectingPort()
{
    if(isOpen())
    {
        return serialport->portName();
    }
    else
    {
        return QString("");
    }
}

bool Serial::waitForRx(int msecs)
{
    return serialport->waitForReadyRead(msecs);
}

void Serial::onFrameEnd()
{
    auto frame = rxBuf;
    rxBuf.clear();

    if(checkRxData(frame)) {
        emit frameIn(frame);
        // emit pkgIn(dataFromeFrame(frame));
    } else {
        qWarning() << "unknown frame:" << QString::fromUtf8(frame);
    }
}

void Serial::onReadyRead()
{
    if(blockingRecv) {
        return;
    }

    // qDebug() << "serial:" << serialport->portName() << "rx bytes:" << serialport->bytesAvailable();
    rxBuf += serialport->readAll();
    if(checkRxData(rxBuf)) {
        frameTimer.stop();

        auto frame = rxBuf;
        rxBuf.clear();
        emit frameIn(frame);
        // emit pkgIn(dataFromeFrame(frame));
    } else {
        // 防止发送端无限地发送
        if(rxBuf.size() > rxMaxSize) {
            rxBuf.clear();
        }

        frameTimer.start();
    }
}

void Serial::onError(QSerialPort::SerialPortError error)
{
    if(error == QSerialPort::NoError)
    {
        return;
    }

    qDebug() << "Serial: Error: " << error;
    switch(error)
    {
    case QSerialPort::ResourceError:
    case QSerialPort::NotOpenError:
        close();
        break;

    default:
        close();
        break;
    }
}

bool Serial::send(char byte)
{
    return (serialport->write(&byte, 1) == 1) ? true : false;
}

bool Serial::send(const QByteArray &data)
{
    // qDebug() << "tx:" << data;
    return (serialport->write(data) == data.size()) ? true : false;
}
